-------------------------------------------------------------------------------
-- ram_rtl.vhd
-------------------------------------------------------------------------------
--
-- This file is part of SKUMLI.
-- Copyright (C) 2011 Davide Giuseppe Monaco (black.ralkass@gmail.com)
--
-- SKUMLI is free software: you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation, either version 3 of the License, or
-- (at your option) any later version.
--
-- SKUMLI is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-- GNU General Public License for more details.
--
-- You should have received a copy of the GNU General Public License
-- along with SKUMLI.  If not, see <http://www.gnu.org/licenses/>.
--
-------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_textio.all;
use ieee.std_logic_unsigned.all;
use std.textio.all;
-------------------------------------------------------------------------------
architecture rtl of ram is

  -- 256 Blocks of 4 Bytes
  type ram_blocks is array (0 to 383) of std_logic_vector(0 to 31);

  signal mem : ram_blocks;

  -- FSM related signals
  signal state : std_logic_vector(1 downto 0);
  signal busy  : std_logic;
  signal q_bus  : std_logic_vector(31 downto 0); -- dout

  -- debug
  signal word0 : std_logic_vector(31 downto 0);
  signal word1 : std_logic_vector(31 downto 0);
  signal word2 : std_logic_vector(31 downto 0);
  signal word3 : std_logic_vector(31 downto 0);

begin -- rtl

  dout <= q_bus;

  -- debug block assignment
  word0 <= mem(0);
  word1 <= mem(1);
  word2 <= mem(2);
  word3 <= mem(3);

-------------------------------------------------------------------------------
  -- this process is used for simulation purpose 
  busy_gen: process (state)
  begin -- busy_gen 

    if state = "01" or state = "10" then
      busy <= '1', '0' after 25 ns; -- simulate component delay

    else
      busy <= '0';

    end if;

  end process busy_gen;

-------------------------------------------------------------------------------
  -- data out is filled with valid data if the following conditions are
  -- satisfied:
  --   1. state is read
  --   2. valid bit is HIGH
  --   3. tag flag is HIGH
  q_bus_gen: process (state)
    -- initialization flag
    variable init    : boolean := false;
    
    -- out support variable
    variable q : std_logic_vector(31 downto 0);

    -- integer index/offset support variables
    variable int_index  : integer;

  begin -- q_bus_gen
-------------------------------------------------------------------------------
--  INITIALIZATION
-------------------------------------------------------------------------------
    if init = false then

      q := (others => '0');
      init := true;

    end if;
-------------------------------------------------------------------------------
--  END INITIALIZATION
-------------------------------------------------------------------------------

    if state = "01" then
      -- calculate block index
      int_index  := conv_integer(addr(31 downto 2));

      q := mem(int_index);

    end if;

    q_bus <= q;

  end process q_bus_gen;

-------------------------------------------------------------------------------
  -- perform write after proper initialization reading a file (simulation purpose)
  write: process (state)
    -- initialization flag
    variable init    : boolean := false;

    -- memory initialization support variables
    file     f : text;
    variable l : line; 
    variable w : std_logic_vector(0 to 31);

    -- integer index/offset support variables
    variable int_index  : integer;

  begin -- write
-------------------------------------------------------------------------------
--  BLOCK INITIALIZATION
-------------------------------------------------------------------------------
    if init = false then

      -- open file for read
      file_open(f, "mem.dat", read_mode);

      -- read the line, catch the word and put it into mem slot
      for i in 0 to 383 loop
        readline(f, l);
        read(l, w);
        mem(i) <= w;
      end loop;

      file_close(f);
      init := true;

    end if;
-------------------------------------------------------------------------------
--  END BLOCK INITIALIZATION
-------------------------------------------------------------------------------

    if state = "10" then
      -- calculate index
      int_index := conv_integer(addr(31 downto 2));

      -- write mem
      mem(int_index) <= din;

    end if;

  end process write;

-------------------------------------------------------------------------------
  main: process (state, rw, cs, busy)

    -- initialization flag
    variable init : boolean := false;

    -- state support variable
    variable s : std_logic_vector(1 downto 0);

  begin -- main
-------------------------------------------------------------------------------
--  STATE INITIALIZATION
-------------------------------------------------------------------------------
    if init = false then

      state <= "00";
      init := true;

    end if;
-------------------------------------------------------------------------------
--  END STATE INITIALIZATION
-------------------------------------------------------------------------------

    case state is

      -- IDLE
      when "00" =>
        if cs = '1' and rw = '0' and busy = '0' then     -- READ
          s := "01";

        elsif cs = '1' and rw = '1' and busy = '0' then  -- WRITE
          s := "10";

        else                                -- IDLE
          s := "00";

        end if;

      -- READ
      when "01" =>
        if busy = '1' then
          s := "01";

        else
          s := "00";

        end if;

      -- WRITE
      when "10" =>
        if busy = '1' then
          s := "10";

        else
          s := "00";

        end if;

      when others =>
        s := "00";

    end case;

    -- NOTE: 1 ns commutation is reserved to:
    --       IDLE -> READ
    --       IDLE -> WRITE
    --       viceversa follows busy signal (10 ns).
    state <= s after 1 ns;
    
  end process main;
-------------------------------------------------------------------------------
  cmb: process (state)
  begin -- cmb

    case state is

      -- IDLE
      when "00" =>
        rdy  <= '1';

      -- READ
      when "01" =>
        rdy  <= '0';

      -- WRITE 
      when "10" =>
        rdy  <= '0';

      when others =>
    end case;

  end process cmb;
-------------------------------------------------------------------------------
end rtl;
